#include "Common.h"
#include "ShaderMap.h"
#include "Shader.h"
#include "Material.h"
#include "VertexFactory.h"

//------------------------------------------
// ShaderMap
//------------------------------------------
ShaderMap::ShaderMap()
{
}
//------------------------------------------
ShaderMap::~ShaderMap()
{
	Clear();
}
//------------------------------------------
Shader* ShaderMap::getShader(const ShaderType* shaderType)
{
	ShaderList::iterator it = mShaders.find(shaderType);
	if (it != mShaders.end())
		return it->second;
	return NULL;
}
//------------------------------------------
void ShaderMap::Clear()
{
	for (ShaderList::iterator it(mShaders.begin()), end(mShaders.end()); it != end; it++)
		delete it->second;
	mShaders.clear();
}
//------------------------------------------
void ShaderMap::Compile(Material* parent, const VertexFactoryType* vertexFactoryType)
{
	// clear first.
	Clear();

	const ShaderType::ShaderTypeList& shaderTypes = ShaderType::getShaderTypeList();
	for (ShaderType::ShaderTypeList::const_iterator it(shaderTypes.begin()), end(shaderTypes.end()); it != end; it++)
	{
		const ShaderType* shaderType = *it;
		if (!shaderType->ShouldCache(parent))
			continue;

		// build shadow map.
		ShaderDefineMap defineMap;
		parent->Define(&defineMap);
		shaderType->Define(&defineMap);
		vertexFactoryType->Define(&defineMap);

		// compile base on the defines.
		Shader* shader = Shader::Compile(shaderType, vertexFactoryType, &defineMap);
		if (shader == NULL)
			continue;

		mShaders[shaderType] = shader;
	}
}
//------------------------------------------


//------------------------------------------
// MaterialShaderMap
//------------------------------------------
MaterialShaderMap::MaterialShaderMap()
{
}
//------------------------------------------
MaterialShaderMap::~MaterialShaderMap()
{
	Clear();
}
//------------------------------------------
Shader* MaterialShaderMap::getShader(const ShaderType* shaderType, const VertexFactoryType* vertexFactoryType) const
{
	VertexFactoryMap::const_iterator it = mVertexFactoryMap.find(vertexFactoryType);
	if (it != mVertexFactoryMap.end())
		return it->second->getShader(shaderType);
	return NULL;
}
//------------------------------------------
void MaterialShaderMap::Clear()
{
	for (VertexFactoryMap::iterator it(mVertexFactoryMap.begin()), end(mVertexFactoryMap.end()); it != end; it++)
		delete it->second;
	mVertexFactoryMap.clear();
}
//------------------------------------------
void MaterialShaderMap::Compile(Material* parent)
{
	// clea first.
	Clear();

	const VertexFactoryType::VertexFactoryTypeList& vertexFactoryTypes = VertexFactoryType::getVertexFactoryTypeList();
	for (VertexFactoryType::VertexFactoryTypeList::const_iterator it(vertexFactoryTypes.begin()), end(vertexFactoryTypes.end()); it != end; it++)
	{
		const VertexFactoryType* vertexFactoryType = *it;
		if (!vertexFactoryType->ShouldCache(parent))
			continue;

		Compile(parent, vertexFactoryType);
	}
}
//------------------------------------------
void MaterialShaderMap::Compile(Material* parent, const VertexFactoryType* vertexFactoryType)
{
	VertexFactoryMap::const_iterator shaderMapIt = mVertexFactoryMap.find(vertexFactoryType);
	if (shaderMapIt == mVertexFactoryMap.end())
		shaderMapIt = mVertexFactoryMap.insert(VertexFactoryMap::value_type(vertexFactoryType, new ShaderMap())).first;

	ShaderMap* shaderMap = shaderMapIt->second;
	shaderMap->Compile(parent, vertexFactoryType);
}
//------------------------------------------